import glob, os, sys

platform = str(Platform())
if 'win' in platform:
    pathSep = '\\'
else:
    pathSep = '/'
    
def makePath(*args):
    return pathSep.join(args)
    
def getSubPaths(path):
    if os.path.isdir(path):
        subFolders = [path]
        for child in glob.glob(makePath(path,'*')):
            subFolders.extend(getSubPaths(child))
        return subFolders
    else:
        return []
        
def getFiles(path, extension):
    if os.path.isdir(path):
        return filter(os.path.isfile, glob.glob(makePath(path,'*' + extension)))
    else:
        return []
        
def getRecFiles(pathList, extension):
    files = []
    for path in pathList:
        files.extend(getFiles(path,extension))
    return files
    
def getFilePaths(fileList):
    pathList = []
    for file in fileList:
        path = file[:file.rfind(pathSep)]
        if path not in pathList:
            pathList.append(path)
    return pathList
    
def flatten(l):
    if type(l) == list:
        ret = []
        for i in l:
            ret.extend(flatten(i))
        return ret
    else:
        return [l]
        
filesToClean = []
def copyFile(source, dest = None):
    if not dest:
        dest = source.split(pathSep)[-1]

    if not env.GetOption('clean'):
        print "copy %s" % (source, dest)
        if 'win' in platform:
            Copy(dest,source)
        else:
            os.system('cp %s %s' % (source, dest))
    filesToClean.append(dest)

#build options
opts = Options()
opts.Add('project', 'Project to compile', 'system')

#build environment
env = Environment()
env.Append(options = opts)
Help(opts.GenerateHelpText(env))
    
#fill options
project = ARGUMENTS.get('project',None)
libsStr = ARGUMENTS.get('libs','')
libs = libsStr.split(',')

#check options
if not project:
    print "ERROR: specify project to compile"
    Exit(1)
elif not os.path.isdir(project):
    print "ERROR: project", project, "not found"
    Exit(1)
    
#search for folders
systemPaths = getSubPaths('system')
projectPaths = getSubPaths(project)
libPaths = [getSubPaths(lib) for lib in libs]

buildPaths = systemPaths + projectPaths
for paths in libPaths:
    buildPaths += paths

#search for files
extensions = ['.cpp','.h']
files = {}
for extension in extensions:
    files[extension] = getRecFiles(buildPaths,extension)
    
incDirs = getFilePaths(files['.h'])

#process libs

libData = {}

def addLibData(newLibData):
    if not newLibData or type(newLibData) != dict:
        return
    for key, data in newLibData.iteritems():
        if libData.has_key(key):
            if type(libData[key]) == list and type(data) == list:
                libData[key].extend(data)
            else:
                libData[key] = data
        else:
            libData[key] = data

for lib in libs:
    libDir = makePath('libs',lib)
    libScons = makePath(libDir,'SConstruct')
    if os.path.isdir(libDir) and os.path.isfile(libScons):
        print "loading library", lib
        addLibData(SConscript(libScons))

if libData.has_key('copyFiles'):
    for filename in flatten(libData['copyFiles']):
        copyFile(filename)

libFilenames = []
if 'win' in platform:
    libExt = '.dll'
else:
    libExt = '.so'
for lib in libs:
    libFilenames += getRecFiles(getSubPaths(makePath('libs',lib)),libExt)
    
for filename in libFilenames:
    if os.path.isfile(filename):
        copyFile(filename)

#process aspects

aspects = []
for filename in files['.h']:
    for line in open(filename).readlines():
        if line.startswith('///SGE_ASPECT'):
            toks = line.split()
            if len(toks) > 1:
                aspectName = toks[1]
            else:
                aspectName = filename.split(pathSep)[-1].split('.')[0]
            if len(toks) > 2:
                aspectType = toks[2]
            else:
                aspectType = aspectName
            if len(toks) > 3:
                aspectFamily = toks[3]
            else:
                aspectFamily = filename.split(pathSep)[0]
            aspects.append((aspectName,aspectType,aspectFamily,filename))

aspectFilename = makePath(project,'aspectFactory.cpp')
aspectFile = open(aspectFilename,'w')

for aspectName, aspectType, aspectFamily, filename in aspects:
    aspectFile.write("#include \"%s\"\n" % filename.split(pathSep)[-1])
    
aspectFile.write("#include \"object.h\"\nusing namespace sge;\n")
aspectFile.write("Aspect* Object::aspectFactory(const String& aspectName) {\n")

for aspectName, aspectType, aspectFamily, filename in aspects:
    aspectFile.write("    if (aspectName == \"%s\")\n" % aspectName)
    className = aspectName[:1].upper() + aspectName[1:]
    aspectFile.write("        return new %s(\"%s\",\"%s\",\"%s\",this);\n" % (className,aspectName,aspectType,aspectFamily))

aspectFile.write("    return 0;\n}\n")

aspectFile.close()

filesToClean.append(aspectFilename)

#build path file
pathFilename = '%s_paths.txt' % project
pathFile = open(pathFilename,'w')
for path in buildPaths:
    pathFile.write("%s\n" % path)
pathFile.close()

filesToClean.append(pathFilename)

#build aspect file
if aspectFilename not in files['.cpp']:
    files['.cpp'].append(aspectFilename)
    
#make flags
flags = "-DSGE_PROJECT=\\\"%s\\\"" % project
if 'win' in platform:
    flags += " /EHsc"
#else:
    #flags += " -g"
    
#link python
systemLibs = ['python2.5','boost_python']

if not 'win' in platform:
    incDirs.append('/usr/include/python2.5')

#build

for name in ['libs','libDirs','incDirs']:
    if not libData.has_key(name):
        libData[name] = []

programName = 'run_' + project
program = env.Program(target = programName, source = files['.cpp'], CPPPATH = incDirs + libData['incDirs'], LIBS = systemLibs + libData['libs'], LIBPATH = libData['libDirs'], CCFLAGS = flags)

for file in filesToClean:
    Clean(program,file)
